﻿using System;
using System.Linq;
using Ibp.Service.Entity.ODAEntity;
using OdaOperation.Core.Parameters;
using OdaOperation.Core.Parameters.Base;
using OdaOperation.Extends;
using OdaOperation.Model;
using Teigha.Core;
using Teigha.TD;

namespace OdaOperation.Core.Creators
{
    public class TableCreator : BaseCreator, ICreate<TableCreator>, IReferenceCreator, ISetParameter<TableCreator, TableParameter>
    {
        private TableParameter m_parameter;

        public TableCreator(OdDbDatabase pDb)
            : base(pDb)
        {
        }

        public void CreateBlockReference(DPoint location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null)
        {
            new BlockReferenceCreator(m_database, m_parameter.BlockName, m_layerName).Create(new OdGePoint3d(location.get_X(), location.get_Y(), location.get_Z()), odGeScale, rotating, mirrorPlane);
        }

        public void CreateBlockReference(OdGePoint3d location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null)
        {
            new BlockReferenceCreator(m_database, m_parameter.BlockName, m_layerName).Create(location, odGeScale, rotating, mirrorPlane);
        }

        public void CreateBlockReference(string layerName, DPoint location, OdGeScale3d odGeScale = null, double rotating = 0.0, OdGePlane mirrorPlane = null, ParameterSet paramters = null)
        {
            new BlockReferenceCreator(m_database, m_parameter.BlockName, layerName).Create(location.ToGePoint3D(), odGeScale, rotating, mirrorPlane);
        }

        public void CreateBlockReference(ReferenceParameter paramter)
        {
            new BlockReferenceCreator(m_database, m_parameter.BlockName, paramter.LayerName).Create(paramter.Location.ToGePoint3D(), paramter.Scale, paramter.Rotating, paramter.MirrorPlane, paramter.Parameters);
        }

        public TableCreator Create()
        {
            m_parameter.Check();
            m_parameter.TableSize.InitFromTable(m_parameter.TableData);
            OdDbObjectId font = TextStyleCreator.GetFont(m_database, m_parameter.FontStyle);
            OdDbBlockTable odDbBlockTable = m_database.getBlockTableId().openObject() as OdDbBlockTable;
            TableSize tableSize = m_parameter.TableSize;
            double width = m_parameter.TableSize.Cols.Sum();
            double yy = m_parameter.TableSize.Rows.Sum();
            OdGePoint3d odGePoint3d = new OdGePoint3d(0.0, yy, 0.0);
            OdGeVector3d xAxis = new OdGeVector3d(1.0, 0.0, 0.0);
            OdGeVector3d yAxis = new OdGeVector3d(0.0, -1.0, 0.0);
            OdDbBlockTableRecord odDbBlockTableRecord;
            if (odDbBlockTable.has(m_parameter.BlockName))
            {
                odDbBlockTableRecord = odDbBlockTable.getAt(m_parameter.BlockName, OpenMode.kForWrite) as OdDbBlockTableRecord;
            }
            else
            {
                odDbBlockTableRecord = OdDbBlockTableRecord.createObject();
                odDbBlockTableRecord.setName(m_parameter.BlockName);
                odDbBlockTable.upgradeOpen();
                odDbBlockTable.add(odDbBlockTableRecord);
                odDbBlockTable.downgradeOpen();
            }

            m_blockTableId = odDbBlockTableRecord.objectId();
            TableItemCreator tableItemCreate = new TableItemCreator(m_database, m_blockTableId, m_layerName, font, odGePoint3d, xAxis, yAxis, m_parameter.FontSize);
            GridCreator gridCreator = new GridCreator(m_database, m_blockTableId, m_layerName);
            if (m_parameter.TableSize.Rows.Count == m_parameter.TableData.Count && m_parameter.TableSize.Cols.Count == m_parameter.TableData.Max((TableRow x) => x.Count))
            {
                gridCreator.CreateGrid(m_parameter.TableSize, odGePoint3d, xAxis, yAxis);
                CreateTableData(font, width, odGePoint3d, xAxis, yAxis, odDbBlockTableRecord, tableItemCreate);
            }
            else
            {
                gridCreator.CreateGrid(m_parameter.TableSize, m_parameter.TableData, odGePoint3d, xAxis, yAxis);
                CreateMixTableData(font, width, odGePoint3d, xAxis, yAxis, odDbBlockTableRecord, tableItemCreate);
            }

            return this;
        }

        private void CreateMixTableData(OdDbObjectId textStyle, double width, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, OdDbBlockTableRecord blockTableRecord, TableItemCreator tableItemCreate)
        {
            if (m_parameter.Title != null)
            {
                OdDbText odDbText = OdDbText.createObject();
                odDbText.setTextString(m_parameter.Title.Title);
                OdGeExtents3d odGeExtents3d = new OdGeExtents3d();
                if (textStyle != null)
                {
                    odDbText.setTextStyle(textStyle);
                }

                odDbText.setHeight(m_parameter.Title.Size);
                odDbText.setDatabaseDefaults(m_database);
                blockTableRecord.appendOdDbEntity(odDbText);
                odDbText.getGeomExtents(odGeExtents3d);
                double num = odGeExtents3d.maxPoint().y - odGeExtents3d.minPoint().y;
                double num2 = odGeExtents3d.maxPoint().x - odGeExtents3d.minPoint().x;
                OdGePoint3d odGePoint3d = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul(width * 0.5 - num2 * 0.5).Add(new OdGeVector3d(yAxis).Mul(-10.0)));
                odDbText.setAlignmentPoint(odGePoint3d);
                odDbText.setPosition(odGePoint3d);
                odDbText.setLayer(m_layerName);
            }

            double num3 = 0.0;
            double num4 = 0.0;
            TableSize tableSize = m_parameter.TableSize;
            TableData tableData = m_parameter.TableData;
            for (int i = 0; i < tableSize.Rows.Count; i++)
            {
                num4 += tableSize.Rows[i];
                TableRow tableRow = tableData[i];
                int num5 = 0;
                foreach (TableItem item in tableRow)
                {
                    if (item == null)
                    {
                        throw new ArgumentNullException($"第{i}行， 第{num5}列 item 不能为空");
                    }

                    double num6 = 0.0;
                    for (int j = 0; j < item.LeftIndex; j++)
                    {
                        num6 += tableSize.Cols[j];
                    }

                    double num7 = num6;
                    for (int k = 0; k < item.ColSpan; k++)
                    {
                        num7 += tableSize.Cols[item.LeftIndex + k];
                    }

                    double num8 = num3;
                    for (int l = 0; l < item.RowSpan; l++)
                    {
                        num8 += tableSize.Rows[i + l];
                    }

                    num5 += item.ColSpan;
                    tableItemCreate.Create(item, num6, num7, num3, num8);
                }

                num3 = num4;
            }
        }

        private void CreateTableData(OdDbObjectId textStyle, double width, OdGePoint3d location, OdGeVector3d xAxis, OdGeVector3d yAxis, OdDbBlockTableRecord blockTableRecord, TableItemCreator tableItemCreate)
        {
            if (m_parameter.Title != null)
            {
                OdDbText odDbText = OdDbText.createObject();
                odDbText.setTextString(m_parameter.Title.Title);
                OdGeExtents3d odGeExtents3d = new OdGeExtents3d();
                if (textStyle != null)
                {
                    odDbText.setTextStyle(textStyle);
                }

                odDbText.setHeight(m_parameter.Title.Size);
                odDbText.setDatabaseDefaults(m_database);
                blockTableRecord.appendOdDbEntity(odDbText);
                odDbText.getGeomExtents(odGeExtents3d);
                double num = odGeExtents3d.maxPoint().y - odGeExtents3d.minPoint().y;
                double num2 = odGeExtents3d.maxPoint().x - odGeExtents3d.minPoint().x;
                OdGePoint3d odGePoint3d = new OdGePoint3d(location).Add(new OdGeVector3d(xAxis).Mul(width * 0.5 - num2 * 0.5).Add(new OdGeVector3d(yAxis).Mul(-10.0)));
                odDbText.setAlignmentPoint(odGePoint3d);
                odDbText.setPosition(odGePoint3d);
                odDbText.setLayer(m_layerName);
            }

            double top = 0.0;
            double num3 = 0.0;
            TableSize tableSize = m_parameter.TableSize;
            TableData tableData = m_parameter.TableData;
            for (int i = 0; i < tableSize.Rows.Count; i++)
            {
                num3 += tableSize.Rows[i];
                double left;
                double num4 = (left = 0.0);
                for (int j = 0; j < tableSize.Cols.Count; j++)
                {
                    num4 += tableSize.Cols[j];
                    TableItem item = tableData[i][j] ?? throw new ArgumentNullException($"第{i}行， 第{j}列 item 不能为空");
                    tableItemCreate.Create(item, left, num4, top, num3);
                    left = num4;
                }

                top = num3;
            }
        }

        public TableCreator SetParameter(TableParameter parameter)
        {
            parameter.Check();
            m_parameter = parameter;
            m_layerName = parameter.LayerName;
            return this;
        }
    }
}